added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / tools / nmake / parser.cpp
blobe128952875c9741fb1c5ddc5fc11d5a77cbebc41
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
14 // ==--==
15 // PARSER.C -- parsing routines
17 // Purpose:
18 // This module contains the NMAKE grammar parser. It parses input and uses the
19 // getToken() routine to get the next token.
21 #include "precomp.h"
22 #ifdef _MSC_VER
23 #pragma hdrstop
24 #endif
26 #include "table.h"
28 // macros that deal w/ the productions stack and the actions function table
30 #define topStack() (stack[top])
31 #define popStackAndReturn() (stack[top--])
32 #define popStack() top--
33 #define pushStack(A) (stack[++top] = A)
34 #define doAction(A) (*(actions[A & LOW_NIBBLE]))()
38 // parse() table-driven parser for makefile grammar
40 // arguments: init global boolean value -- TRUE if tools.ini is the
41 // file being parsed
43 // actions: initializes the stack (by pushing the empty-stack symbol
44 // and the start symbol)
45 // keeps track of current line (because the lexer may have
46 // read '\n' as a delimiter, and will thus be one line
47 // ahead of the parser)
48 // while the stack is not empty
49 // if the top symbol on the stack is an action
50 // do the action, popping the stack
51 // if the symbol on top of the stack now is a token
52 // if it's not the token we're expecting
53 // syntax error, halt
54 // else
55 // pop token off the stack
56 // if the top symbol on the stack is an action
57 // do the action, popping the stack
58 // reset curent line to lexer's current line
59 // get another token (use the lookahead token
60 // if it exists, and if it had caused the
61 // lexer's line count to be incremented,
62 // decrement our local count because we're
63 // still parsing the preceding line)
64 // else the symbol on top of the stack is a production
65 // find next production to do in production table
66 // (based on current input token and current
67 // production on stack)
68 // if the table entry is an error condition
69 // print appropriate error message, halt
70 // pop current production off stack
71 // if the "next production" can be one of two
72 // things, decide which one to use by peeking
73 // at the next input token and looking in the
74 // "useAlternate" decision table (using the last
75 // production and next input token as indexes)
76 // if the appropriate table entry is YES,
77 // use the next larger production from the one
78 // we found in the production table
79 // push each symbol in the production on the stack
80 // loop
82 // modifies: stack production stack, static to this module
83 // top index of current symbol at top of stack
85 // Use extreme care in modifying this code or any of the tables associated
86 // with it. The methods used to build the tables are described in detail
87 // in grammar.h and table.h. This parser is based on the predictive parser
88 // described on pages 186-191 of Aho & Ullman "Principles of Compiler Design."
89 // I have modified it to use an extra symbol of lookahead to deal w/ an
90 // ambiguous grammar and have added code to perform appropriate actions as
91 // it parses the productions.
93 void
94 parse()
96 UCHAR stackTop, token, nextToken = 0;
97 register unsigned n, i;
99 firstToken = TRUE; // global var
100 pushStack(ACCEPT); // init stack
101 pushStack(START);
102 currentLine = line;
103 token = getToken(MAXBUF,START); // get first token
104 while ((stackTop = topStack()) != ACCEPT) {
105 if (ON(stackTop,ACTION_MASK)) {
106 doAction(popStackAndReturn());
107 } else if (ON(stackTop,TOKEN_MASK)) {
108 if (stackTop != token) {
109 makeError(currentLine,SYNTAX+FATAL_ERR,buf);
110 } else {
111 popStack();
112 #ifdef DEBUG_ALL
113 printf ("DEBUG: parse 1: %d\n", line);
114 #endif
115 if (ON(topStack(),ACTION_MASK)) {
116 doAction(popStackAndReturn());
118 #ifdef DEBUG_ALL
119 printf ("DEBUG: parse 2: %d\n", line);
120 #endif
121 currentLine = line;
122 if (nextToken) { // if we already
123 if (*buf == '\n') --currentLine; // have a token,
124 token = nextToken; // use it . . .
125 nextToken = 0;
126 } else {
127 token = getToken(MAXBUF,topStack());
128 currentLine = line;
131 } else {
132 n = table[stackTop][token & LOW_NIBBLE];
133 #ifdef DEBUG_ALL
134 printf ("DEBUG: parse 3: %x %d %x %x\n", n, stackTop, token & LOW_NIBBLE, token);
135 #endif
136 if (ON(n,ERROR_MASK)) {
137 #ifdef DEBUG_ALL
138 printf ("DEBUG: parse 4: %d %s\n", line, buf);
139 #endif
140 makeError(currentLine,n+FATAL_ERR,buf);
142 popStack();
143 if (ON(n,AMBIG_MASK)) { // 2 possible prod
144 n &= LOW_NIBBLE; // only use 4 bits
145 if (!nextToken) { // peek to decide
146 nextToken = getToken(MAXBUF,stackTop);
148 n += (useAlternate[stackTop][nextToken & LOW_NIBBLE]);
150 for (i = productions[n][0]; i; --i) { // put production
151 pushStack(productions[n][i]); // on stack
153 } // 1st elt in prod
154 } // is its length
155 popStack(); // pop the ACCEPT off the stack